

import { defineAsyncComponent, toRaw, nextTick } from 'vue';
import DebugController from '../frontpage/js/htmls/debugger/DebugSider.mjs';
import LogView from '../frontpage/components/LogView/LogView.mjs'
let IframePreviewer = defineAsyncComponent(() => {
    return new Promise((resolve, reject) => {
        axios('../iframeconnector/IframePreviewer.html').then(({ data }) => {
            resolve({
                name: 'IframePreviewer',
                components: { LogView },
                props: [],
                template: data,
                data() {
                    return {
                        components: [],
                        modal: true,
                        Modal: null,
                        manager: null,
                        breakpoints: [],
                        scene: null,
                        bytes: null,
                        title: '',
                        isDebug: false,
                        id: IframeSimulator.id++,
                        url: null,
                        mousePosition: { x: 0, y: 0 },
                        style: {
                            width: '375px',
                            height: '600px',
                            widthWithDev: '900px',
                            borderBottom: '1px solid #e8eaec',
                            borderRight: '1px solid #e8eaec'
                        },
                        modalClasses: ['jspreviewer'],
                        maskStyle: {
                            display: 'block',
                            width: '100%'
                        },
                        iframeStyle: {},
                        gridX: 0, gridY: 0,
                        tool: null,
                        scene: null
                    }
                },
                watch: {
                    "Modal.dragData.dragging": {
                        handler: function (dragging) {
                            if (dragging) {
                                this.mask();
                            } else {
                                let style = this.$refs.Modal.contentStyles;
                                let left = parseFloat(style.left);
                                let top = parseFloat(style.top);
                                let width = parseFloat(style.width);
                                if (left > window.innerWidth) {
                                    style.left = (window.innerWidth - 40) + 'px';
                                } else {
                                    if (left < - width + 60) {
                                        style.left = - width + 60 + 'px';
                                    }
                                }
                                if (top < 0) {
                                    style.top = '0px';
                                }
                                if (top > window.innerHeight - 30) {
                                    style.top = window.innerHeight - 30 + 'px';
                                }
                            }
                        },
                        deep: true
                    }
                },
                computed: {
                },
                methods: {
                    addComponent(compInfo) {
                        console.log(compInfo);
                        this.components.push(compInfo);
                        this.tool = 'component';
                    },
                    async screenshot(evt) {
                        let imgBlob = evt.data.arg;
                        let buffer = await imgBlob.arrayBuffer();
                        OpenBlock.VFS.partition.info.put('thumbnail.jpg', buffer);
                        let base64 = OpenBlock.Utils.arrayBufferToBase64(buffer);

                        OpenBlock.VFS.partition.config.get('project.json', p => {
                            p.thumbnail = 'data:image/png;base64, ' + base64;
                            OpenBlock.VFS.partition.config.put('project.json', p);
                        });
                    },
                    saveAsThumbnail() {
                        let screenshot = {
                            "cmd": "screenshot"
                        };
                        this.$refs.iframe.contentWindow.postMessage(screenshot);
                    }, requestFullScreen() {
                        let screenshot = {
                            "cmd": "requestFullScreen"
                        };
                        this.$refs.iframe.contentWindow.postMessage(screenshot);
                    },
                    pause() {
                        let runProjectCmd = {
                            "cmd": "pause",
                        };
                        this.$refs.iframe.contentWindow.postMessage(runProjectCmd);
                    },
                    sendMessage(msg) {
                        this.$refs.iframe.contentWindow.postMessage(msg);
                    },

                    restart() {
                        let runProjectCmd = {
                            "cmd": "restart",
                        };
                        this.$refs.iframe.contentWindow.postMessage(runProjectCmd);
                    },
                    gridChange() {
                        let arg = { x: Math.abs(parseInt(this.gridX)), y: Math.abs(parseInt(this.gridY)) };
                        let drawGrid = {
                            "cmd": "drawGrid",
                            "arg": arg
                        };
                        this.$refs.iframe.contentWindow.postMessage(drawGrid);
                        console.log(arg);
                    },
                    changeScreen(evt) {
                        this.style.height = evt.target.value;
                    },
                    onVisibleChange(v) {
                        if (!v) {
                            OB_IDE.removeComponent(this);
                        }
                    },
                    receiveMessage(event) {
                        if (event.source != this.$refs.iframe.contentWindow) {
                            return;
                        }
                        let cmd = event.data.cmd;
                        if (this[cmd]) {
                            try {
                                this[cmd](event);
                            } catch (e) {
                                console.error(e);
                            }
                        }
                    },
                    mousemove(evt) {
                        let v = evt.data.arg;
                        this.mousePosition = v;
                    },
                    debug(evt) {
                        // this.$refs['logview'].debug(evt);
                        let logview = this.$refs['logview'];
                        if (logview) {
                            let msg = evt.data;
                            let { name, args, level, stack, block } = msg;
                            logview.debug(name, args, level, stack, block);
                        }
                    },
                    msg(evt) {
                        let msg = evt.data.arg;
                        if (msg && msg.format) {
                            msg.content = sprintf(OB_IDE.$t(msg.info.title), msg.info.args);
                        }
                        this.lastMsg = msg;
                    },
                    log(evt) {
                        let v = evt.data.arg;
                        this.$refs['logview'].putLog(v);
                        this.lastMsg = v;
                    },
                    onLogLevelChange(arg) {
                        let drawGrid = {
                            "cmd": "setLogFilter",
                            "arg": arg
                        };
                        this.$refs.iframe.contentWindow.postMessage(drawGrid);
                    },
                    _runProject(bytes, scene, transfer, title, breakpoints = []) {
                        this.bytes = bytes;
                        this.scene = scene;
                        this.breakpoints = breakpoints;
                        let assets = {};
                        let arr_assets = transfer || [];
                        if (OpenBlock.VFS.partition.assets) {
                            let datas = OpenBlock.VFS.partition.assets._storage.datas
                            for (let key in datas) {
                                let d = datas[key].slice(0);
                                assets[key] = d;
                                arr_assets.push(d);
                            }
                        }
                        bytes = toRaw(bytes);
                        assets = toRaw(assets);
                        breakpoints = toRaw(breakpoints);
                        let runProjectCmd = { "cmd": title, bytes, assets, breakpoints };
                        let iframe = this.$refs.iframe;
                        iframe.contentWindow.window.onload = () => {
                            iframe.contentWindow.postMessage(runProjectCmd, arr_assets);
                        };
                        iframe.contentWindow.postMessage(runProjectCmd, arr_assets);
                    },
                    runProject(bytes, scene, transfer) {
                        this.isDebug = false;
                        this._runProject(bytes, scene, transfer, "runProject");
                    },
                    debugProject(bytes, scene, transfer, breakpoints = []) {
                        this.isDebug = true;
                        this.tool = 'devTool'
                        this._runProject(bytes, scene, transfer, "debugProject", breakpoints);
                    },
                    onClickIframeMask() {
                        this.unmask();
                        this.modalClasses = ['jspreviewer', 'current'];
                        nextTick().then(() => {
                            this.$refs.iframe.focus();
                            this.$refs.iframe.contentWindow.focus();
                        });
                    },
                    mask() {
                        let iframe = this.$refs.iframe;
                        this.maskStyle.display = 'block';
                        this.maskStyle.width = iframe.parentElement.clientWidth + 'px';
                    },
                    unmask() {
                        this.maskStyle.display = 'none';
                    },
                    unmarkCurrent() {
                        this.modalClasses = ['jspreviewer'];
                        this.mask();
                    },
                    markCurrent() {
                        this.modalClasses = ['jspreviewer', 'current'];
                        this.unmask();
                    },
                    onDebugpointChange(eventName, breakpoint) {
                        let iframe = this.$refs.iframe;
                        iframe.contentWindow.postMessage({ 'cmd': 'debug', method: eventName + 'Breakpoint', args: [(DebugController.breakpointKey(breakpoint))] });
                    },
                },
                mounted() {
                    DebugController.registerBreakpointListener('IframeSimulator-' + this.id, this.onDebugpointChange.bind(this));
                    this.Modal = this.$refs.Modal;
                    window.addEventListener("message", this.receiveMessage);
                    let iframe = this.$refs.iframe;
                    this.unmask();
                    let that = this;
                    iframe.onload = () => {
                        if (this.isDebug) {
                            this.debugProject(this.bytes, this.scene, null, this.breakpoints);
                        } else {
                            this.runProject(this.bytes, this.scene);
                        }
                        iframe.onblur = this.unmarkCurrent;
                        iframe.contentWindow.onblur = this.unmarkCurrent;
                        iframe.contentDocument.onblur = this.unmarkCurrent;
                        iframe.onfocus = this.markCurrent;
                        iframe.contentWindow.onfocus = this.markCurrent;
                        iframe.contentDocument.onfocus = this.markCurrent;
                        nextTick().then(() => {
                            this.markCurrent();
                            iframe.focus();
                            iframe.contentWindow.focus();
                        });
                    };
                },
                beforeUnmount() {
                    DebugController.unregisterBreakpointListener('IframeSimulator-' + this.id);
                    window.removeEventListener('message', this.receiveMessage);
                    let i = this.manager.windows.indexOf(this);
                    this.manager.windows.splice(i, 1);
                }
            })
        })
    })
});
export default class IframeSimulator {
    static id = 0;
    windows = [];
    browser_run_window;
    url = '../jsruntime/test/index.html';
    componentMap = new Map();
    constructor(url) {
        if (url) {
            this.url = url;
        }
    }
    addComponent(name, icon, component, props) {
        if (!this.componentMap.has(name)) {
            component = toRaw(component);
            this.componentMap.set(name, { name, icon, component, props });
        } else {
            throw Error('重复组件: ' + name);
        }
    }
    removeComponent(name) {
        this.componentMap.delete(name);
    }
    runProject(buf, scene, transfer) {
        if (this.windows.length == 0) {
            this.newWindow(buf, scene, transfer);
        } else {
            let ws = this.windows.filter(w => w.sceneID == scene.id);
            if (ws.length > 0) {
                ws.forEach(w => {
                    w.title = scene.name;
                    w.runProject(buf, scene, transfer);
                });
            } else {
                this.newWindow(buf, scene, transfer);
            }
        }
    }
    debugProject(buf, scene, transfer, breakpoints) {
        let ws = this.windows.filter(w => w.sceneID == scene.id);
        if (ws.length > 0) {
            let w = ws[0];
            w.title = scene.name;
            w.debugProject(buf, scene, transfer, breakpoints);
        } else {
            this.newWindow(buf, scene, transfer, true, breakpoints);
        }
    }
    standaloneWindow(bytes, scene) {
        let wait = false;
        if ((!this.browser_run_window) || this.browser_run_window.closed) {
            this.browser_run_window = window.open(this.url, 'ob_run_window', "width=375,height=540,resizable,scrollbars=no,status=no,alwaysRaised=on,top=100,left=100");
            wait = true;
        }
        let assets = {};
        let arr_assets = [];
        if (VFS.partition.assets) {
            let datas = VFS.partition.assets._storage.datas
            for (let key in datas) {
                let d = datas[key].slice(0);
                assets[key] = d;
                arr_assets.push(d)
            }
        }
        let runProjectCmd = { "cmd": "runProject", bytes, assets };
        if (wait) {
            this.browser_run_window.onload = () => {
                this.browser_run_window.postMessage(runProjectCmd, arr_assets);
                this.browser_run_window.focus();
            };
        } else {
            this.browser_run_window.postMessage(runProjectCmd, arr_assets);
            this.browser_run_window.focus();
        }

    }
    async newWindow(buf, scene, transfer, debug, breakpoints) {
        let win = await OB_IDE.addComponent(IframePreviewer);
        win.title = scene.name;
        win.manager = this;
        win.sceneID = scene.id;
        win.url = this.url;
        win.breakpoints = breakpoints;
        this.componentMap.forEach((comp, key) => {
            win.addComponent(comp);
        });
        this.windows.push(win);
        if (debug) {
            win.debugProject(buf, scene, transfer, breakpoints);
        } else {
            win.runProject(buf, scene, transfer);
        }
    }
}